Object-Orientated Code

TAD

Introduction

We've got those boring definitions out of the way in the previous article, so let's turn our attention to some very simple OO code using these fancy names again. Remember this is focused towards Flash 5/Flash MX action-scripting.

The 'Ruler' Class example

The class we are going to define and use is for an imaginary 'ruler' -- the type used to measure small distances. This is not going to be an actual ruler but instead of kind of storage object for a unit of length. "Why?" you may ask, well it was the best I could think up at the time #;o) Our 'ruler' class will need to store a universal unit of measurement and provide methods() that will automatically convert its universal length into Centimetres, Metres, Inches or even Miles.

The 'Object' object

Again, let's quickly remind ourselves of this basic, building-block or root object on which every other object is based. It has the following methods:

	.toString()
	.valueOf()

It also has a 'primary-value'. This is the value which the two methods above return as a string object or as a number object. This seems to be the default attribute of every object you create. This is ideal for our task. We'll use the primary-value to store the universal unit of measurement for our ruler class and create two methods to replace to default .toString( ) and .valueOf( ) ones.

Our 'ruler' class

Simply put, a property is a data variable (or sub-object) assigned to an object. You can think of it like a member of a data-structure, or an element in an array with its own unique name and value. Just like members of a structure properties use the '.' dot notation, like this:

function Ruler( initvalue ) {
	// constructor ('init') code here //
	this.theLength = initvalue;

	// our '.toString( )' method //
	Ruler.prototype.toString = function() {
		return this.theLength;
	}

	// our '.valueOf( )' method //
	Ruler.prototype.valueOf = function() {
		return this.theLength;
	}
}

Creating an object

Having defined the Class for the object we can instantiate it to create a new object. We haven't chosen a unit of measurement for our primary-value, so let's use Inches.

	MonitorSize = new Ruler(17);

We have passed the number '17' to the object's constructor which stored this number in the .theLength property. At the moment we have 3 different ways to retrieve this value from the MonitorSize object.

	trace ( MonitorSize.theLength );
	trace ( MonitorSize.toString() );
	trace ( MonitorSize.valueOf() );

When we use an object in an expression (eg. a = MonitorSize + 2) it will automatically call either the .toString( ) or the .valueOf( ) method depending on the type of data value we need for the expression.

	// this will call the .valueOf() method //
	trace ( MonitorSize+1 );

	// this uses the .toString() method //
	trace ( MonitorSize );

Say we wanted to format the universal unit value and display it as a string (such as "19 inches") then we modify the .toString( ) method to perform this action.

	// our '.toString( )' method //
	Ruler.prototype.toString = function() {
		return this.theLength + " inches";
	}

All of this could quite easily be done using a variable and some functions to format the output string, like this:

MonitorSize = 17;

function Ruler_toString ( theLength ) {
		return theLength + " inches";
}

trace ( Ruler_toString(MonitorSize) ); 

At the moment the only real difference is that our 'Ruler' class has grouped all the data and methods (functions) together into one place. That's one of the main benefits of Object-Orientated programming. The object (in our example the MonitorSize object) knows which functions and data belongs to itself. We will see later on that this help naming function-like methods so much easier.

A big difference between OO and Functions

One of the biggest differences between normal function-based (or procedure-based) programming and Object-Orientated programming is that in most cases you never need to pass parameters between related operations. This is because the .methods( ) already have access to the data (by using the this keyword to operate on itself). This is an important aspect of OOP and can reduce the chance of bugs where the wrong type of data is used by the wrong sub-routine.

// a Function/Procedure
//
	<destination> = Function ( <source> )

In OO the order is reversed. So we kinda have the data before the operation.

// an OO example //
//
	<object> . methodName( <source> )

In many cases we don't need to specify the source parameter because we will operate on the object itself using the this keyword).

// an OO example //
	<object> .methodName()

Different units of measurement

Suppose we wanted to display the MonitorSize in millimetres or Miles. Well we just need to add some new methods to our Ruler class then every object instance will have access to some new functions. We can even extend the capabilities of the Ruler class to automatically convert different units of measurement into our universal one.

	// some new methods //
	Ruler.prototype.getMillimetres = function() {
		return this.theLength * 25.3995;
	}
	Ruler.prototype.setMillimetres = function( theValue ) {
		this.theLength = theValue * 0.03937;
	}

We can now change the MonitorSize by using the .setMillimetres( ) method like this:

	MonitorSize.setMillimetres(300);

Getters and Setters

In the example above we used methods to access the universal unit of measurement and convert it into/from millimetres. This could have been done using Getter and Setter functions to read and write a specific property of the object. We could have created a fake 'Millimetres' or 'Miles' property and converted the universal measurement behind the scenes like this:

	Ruler.prototype.addProperty(
		 "Millimetres"
		,function() { return this.theLength * 25.3995; }
		,function(n) { this.theLength = n * 0.03937; }
	)

The above adds a property called (yeah) 'Millimetres' to our Ruler class and defined the Getter (read) and Setter (write) functions. We can now access the 'fake' .Millimetres property and it will automatically convert to and from the universal measurement value in real .theLength property.

	// invoke the hidden 'Setter' function //
	MonitorSize.Millimetres = 450;

	// invoke the hidden 'Getter' function //
	trace ( MonitorSize.Millimetres );

Closing words

That's another article finished. I hope it has proved to you that the principles of Object-Orientated Programming is pretty easy. Dig behind the scenes of a OO language and you will find all the familiar things that any function/procedure based language has. I wished someone had explained all this a while ago. It would have saved me a hell of a lot of reading.

Happy Coding

TAD